package br.com.gentech.commons.model.repository;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;

import org.apache.log4j.Logger;

import br.com.gentech.commons.model.entity.BusinessException;
import br.com.gentech.commons.model.entity.IdentifiableEntity;

@Stateless
public class RepositoryBean<Entidade extends IdentifiableEntity<OID>, OID> implements Repository<Entidade, OID>{
	private static final Logger logger = Logger.getLogger(RepositoryBean.class);

	@PersistenceContext(type = PersistenceContextType.TRANSACTION)
	private EntityManager entityManager;
	protected final EntityManager getEntityManager(){ return entityManager; }

	/* (non-Javadoc)
	 * @see br.com.gentech.commons.model.repository.Repository_#save(Entidade)
	 */
	public Entidade save(Entidade unsaved) throws BusinessException {
		if(unsaved.getOID() == null){
			entityManager.persist(unsaved);
			logger.debug("Entidade criada com sucesso. ID = '"+ unsaved.getOID() + "'");
		}else{
			entityManager.merge(unsaved);
			logger.debug("Alteração da entidade, [ID='"+ unsaved.getOID() +"'], executada com sucesso." );
		}
	
		return unsaved;
	}

	/* (non-Javadoc)
	 * @see br.com.gentech.commons.model.repository.Repository_#remove(Entidade)
	 */
	public void remove(Entidade saved) throws BusinessException {
		entityManager.remove( getReference((Class<Entidade>) saved.getClass(), saved.getOID()) );
	}

	/* (non-Javadoc)
	 * @see br.com.gentech.commons.model.repository.Repository_#remove(java.lang.Class, OID)
	 */
	public void remove(Class<Entidade> type, OID id) {
		entityManager.remove( getReference(type, id) );
	}

	private Entidade getReference(Class<Entidade> type, OID id) {
		return entityManager.getReference(type, id);
	}

	/* (non-Javadoc)
	 * @see br.com.gentech.commons.model.repository.Repository_#find(java.lang.Class, OID)
	 */
	public Entidade find(Class<Entidade> type, OID id) {
		return entityManager.find(type, id);
	}

	/* (non-Javadoc)
	 * @see br.com.gentech.commons.model.repository.Repository_#find(java.lang.Class)
	 */
	@SuppressWarnings("unchecked")
	public List<Entidade> find(Class<Entidade> type) {
		return  entityManager.createQuery("select e from "+ type.getName() +" e").getResultList();
	}

	public List<Entidade> findWithNamedQuery(Enum<?> namedQueryName){
        return getEntityManager().createNamedQuery(namedQueryName.toString()).getResultList();
    }
	public List<Entidade> findWithNamedQuery(Enum<?> namedQueryName, Map<String, Object> parameters){
		Set<Entry<String, Object>> rawParameters = parameters.entrySet();
        Query query = getEntityManager().createNamedQuery(namedQueryName.toString());

        for (Entry<String, Object> entry : rawParameters) {
            query.setParameter(entry.getKey(), entry.getValue());
        }

        return query.getResultList();
	}
}